﻿module Main where
import System.IO
import Data.Char
import Data.Time
import System.Time
import System.Locale
import System.Environment
import Text.Regex.Posix


main = do {
	putStrLn "==============================================";
	putStrLn "|   Projekt: Książka adresowa                |";
	putStrLn "|   Autorzy: Michał Pawluczuk, Piotr Wróbel  |";
	putStrLn "==============================================";
	menu;
}

-- główna pętla programu, interakcja z użytkownikiem
menu = do {
	putStrLn "-----------------MENU GLOWNE--------------------"; 
	putStrLn "(1) Dodanie/edycja informacji o osobach";
	putStrLn "(2) Dodanie/edycja informacji o grupach";
	putStrLn "(3) Powiązanie osób z grupami";
	putStrLn "(4) Wyszukiwanie osób";
	putStrLn "(5) Wyświetlenie wszystkich osób";
	putStrLn "(6) Wyświetlenie wszystkich grup";
	putStrLn "(7) Wyświetlenie wszystkich asocjacji";
	putStrLn "(8) W dniu dzisiejszym urodziny obchodzą";
	putStrLn "(q) Wyjście";

	putStrLn "Wybierz polecenie:";
	cmd <- getLine;

	case cmd of
		"1" -> do {
			putStrLn "(w) Wprowadzenie informacji o osobie";
			putStrLn "(m) Modyfikacja informacji o osobie";
			putStrLn "(u) Usuniecie informacji o osobie";
			opt <- getLine;
			case opt of
				"w" -> do {
					name<-checkPattern litery "Podaj imie: ";
                    
                    surname<-checkPattern litery "Podaj nazwisko: ";
					
					firm<-checkPattern litery "Podaj nazwę firmy: ";
					
					number <-checkPattern telefony "Podaj nr telefonu: (kom lub stacjonarny, bez zera na początku)";
										
					mail <-checkPattern mail "Podaj mail: ";

					birth <-checkPattern daty "Podaj datę urodzin: (YYYY-MM-DD)";
                    
					addPerson name surname firm number mail birth;                                                    
					menu;
				};
				"m" -> do {
				    putStrLn "Podaj nr telefonu osoby, którą chcesz edytować: ";
					nr_tel <- getLine;
					
					putStrLn "EDYTUJ:";
					putStrLn "(i) Imie (n) Nazwisko (f) Firma (t) Telefon  (e) E-mail  (d) Datę urodzenia";
					edit_choice <- getLine;
					
					case edit_choice of
						"i" -> do {
							newValue<-checkPattern litery "Podaj nowe imie: ";
							modifyDataPerson "d:/persons.txt" nr_tel newValue 1;
							menu;
						};
						
						"n" -> do {
							newValue<-checkPattern litery "Podaj nowe nazwisko: ";
							modifyDataPerson "d:/persons.txt" nr_tel newValue 2;
							menu;
						};
						
						"f" -> do {
							newValue<-checkPattern litery "Podaj nową nazwę firmy: ";
							modifyDataPerson "d:/persons.txt" nr_tel newValue 3;
							menu;
						};
						
						"t" -> do {
							newValue<-checkPattern telefony "Podaj nowy nr telefonu";
							modifyDataPerson "d:/persons.txt" nr_tel newValue 4;
							modifyDataPersonPhoneAssoc "d:/groupspersons.txt" nr_tel newValue;
							menu;
						};
						
						"e" -> do {
							newValue<-checkPattern mail "Podaj nowy e-mail: ";
							modifyDataPerson "d:/persons.txt" nr_tel newValue 5;
							menu;
						};
						
						"d" -> do {
							newValue<-checkPattern daty "Podaj nową datę urodzin: (YYYY-MM-DD)";
							modifyDataPerson "d:/persons.txt" nr_tel newValue 6;
							menu;
						};
						
						otherwise -> do {
						putStrLn "Wybrano niezrozumiałe polecenie";
						menu;
						};
				};
				
				"u" -> do {
					putStrLn "Podaj nr telefonu osoby, którą chcesz usunąć: ";
					nr_tel <- getLine;
					deleteDataPerson "d:/persons.txt" nr_tel; 
					deleteDataPersonAssoc "d:/groupspersons.txt" nr_tel;
					menu;
				};
				otherwise -> do {
					putStrLn "Wybrano niezrozumiałe polecenie";
					menu;
				};
		}
		"2" -> do {
							putStrLn "(w) Wprowadzenie nowej grupy";
							putStrLn "(m) Modyfikacja grupy";
							putStrLn "(u) Usunięcie grupy";
							putStrLn "(s) Scalenie grup";
							opt <- getLine;
							case opt of
								"w" -> do {
									putStrLn "Podaj symbol grupy: ";
									symbol <- getLine;
									putStrLn "Podaj nazwe grupy: ";
									groupName <- getLine;
									addGroup symbol groupName;
									menu;
								};
								"m" -> do {
									putStrLn "Podaj dotychczasowy symbol grupy: ";
									symbol <- getLine;
									putStrLn "Podaj nowy symbol grupy: ";
									newSymbol <- getLine;
									putStrLn "Podaj nową nazwę grupy: ";
									newgroupName <- getLine;
									modifyGroupAssoc symbol newSymbol;
									modifyGroup symbol newSymbol newgroupName;
									menu;
								};
								"u" -> do {
									putStrLn "Podaj symbol grupy do usunięcia: ";
									symbol <- getLine;
									deleteGroupAssoc symbol;
									deleteGroup symbol;
									menu;
								};
								"s" -> do {
									putStrLn "Podaj symbol grupy źródłowej: ";
									fromGroupSymbol <- getLine;
									putStrLn "Podaj symbol grupy docelowej: ";
									toGroupSymbol <- getLine;
									mergeGroups fromGroupSymbol toGroupSymbol;
									deleteGroupAssoc fromGroupSymbol;
									deleteGroup fromGroupSymbol;
									menu;
								};
								otherwise -> do {
									putStrLn "Wybrano niezrozumiałe polecenie";
									menu;
								};
						}
		"3" -> do {
							putStrLn "(w) Dodanie osoby do grupy";
							putStrLn "(u) Usuwanie osoby do grupy";
							opt <- getLine;
							case opt of
								"w" -> do {
									putStrLn "Podaj telefon: ";
									phone <- getLine;
									putStrLn "Podaj symbol grupy: ";
									symbol <- getLine;
									addGroupAssociation symbol phone;
									menu;
								};
								"u" -> do {
									putStrLn "Podaj telefon: ";
									phone <- getLine;
									putStrLn "Podaj symbol grupy: ";
									symbol <- getLine;
									removeGroupAssociation "d:/groupspersons.txt" symbol phone;
									menu;
								};
								otherwise -> do {
									putStrLn "Wybrano niezrozumiałe polecenie";
									menu;
								};
						}
		"4" -> do {
							putStrLn "Wyszukiwanie po:";
							putStrLn "(q) Imie (w) Nazwisko (e) Firma (r) Telefon  (t) E-mail  (y) Grupa";
							category <- getLine;
							putStrLn "Podaj ciag znakow do wyszukania: ";
							pattern <- getLine;
							case category of
								"q" -> do {
									findBy "d:/persons.txt" pattern 1 False;
									menu;
								};
								"w" -> do {
									findBy "d:/persons.txt" pattern 2 False;
									menu;
								};
								"e" -> do {
									findBy "d:/persons.txt" pattern 3 False;
									menu;
								};
								"r" -> do {
									findBy "d:/persons.txt" pattern 4 False;
									menu;
								};
								"t" -> do {
									findBy "d:/persons.txt" pattern 5 False;
									menu;
								};
								"y" -> do {
									findByGroup "d:/groupspersons.txt" pattern False;
									menu;
								};
								otherwise -> do {
									putStrLn "Wybrano niezrozumiałe polecenie";
									menu;
								};
						}
		"5" -> do {
							printFile "d:/persons.txt";
							menu
		}
		"6" -> do {
							printFile "d:/groups.txt";
							menu
		}
		"7" -> do {
							printFile "d:/groupspersons.txt";
							menu
		}
		"8" -> do {
							hand <- openFile "d:/persons.txt" ReadWriteMode;
							yp <- findingBirthDay hand [];
							hClose hand;
							printingJubilat yp;
							menu
		}
		"q" -> return();
		otherwise -> do {
			putStrLn "Wybrano niezrozumiałe polecenie";
			menu;
		};
}

-- funckja służąca do usuwania osoby z grupy
removeGroupAssociation fname groupSymbol phone = catch ( do { 
							handle <- openFile fname ReadWriteMode;
							contents <- hGetContents handle;
							contents2 <- return $! (contents);
							hClose handle;
							handle <- openFile fname WriteMode;
							deleteRowPersonAssocGroup handle contents2 (groupSymbol++" "++phone) False  ;
							hClose handle;
						} ) errorHandler
						where
							errorHandler e = ioError e
							
-- funckja służąca do usuwania osoby z grupy, operuje na uchwycie do pliku
deleteRowPersonAssocGroup hdl contents searchVal debug = do {
							if (findPattern contents ("\n")) then do {
								if (findPatternEx searchVal (getRow contents)) then do {
									hPutStrLn hdl "" ;
									contents <- return(removeRow contents);
									deleteRowPersonAssocGroup hdl (noNewLine (removeRow contents)) searchVal True ;
								}
								else do {
									hPutStrLn hdl (getRow contents);
									deleteRowPersonAssocGroup hdl (noNewLine (removeRow contents)) searchVal debug ;
								}
							}
							else 
								if (debug==False) then
									putStrLn ("Nie znaleziono wpisu: "++searchVal)
								else 
									putStrLn ("Wpis "++searchVal++" zostal usuniety");
						}
						

-- funkcja sluzaca do usuniecia danych osoby
deleteDataPerson fname searchVal = catch ( do { 
							handle <- openFile fname ReadWriteMode;
							contents <- hGetContents handle;
							contents2 <- return $! (contents);
							hClose handle;
							handle <- openFile fname WriteMode;
							deleteRowPerson handle contents2 searchVal False 4 ;
							hClose handle;
						} ) errorHandler
						where
							errorHandler e = ioError e
							
-- funkcja sluzaca do usuniecia danych osoby, wyszukuje wiersz na podstawie podanej kolumny searchByColumn i usuwa wiesz
deleteRowPerson hdl contents searchVal debug searchByColumn  = do {
							if (findPattern contents ("\n")) then do {
								if (findPatternEx searchVal (getColumn (getRow contents) searchByColumn)) then do {
									hPutStrLn hdl "" ;
									contents <- return(removeRow contents);
									deleteRowPerson hdl (noNewLine (removeRow contents)) searchVal True searchByColumn ;
								}
								else do {
									hPutStrLn hdl (getRow contents);
									deleteRowPerson hdl (noNewLine (removeRow contents)) searchVal debug searchByColumn ;
								}
							}
							else 
								if (debug==False) then
									putStrLn ("Nie znaleziono wpisu: "++searchVal)
								else 
									putStrLn ("Wpis "++searchVal++" zostal usuniety");
						}
						
-- funkcja sluzaca do usuniecia osoby z asocjacji
deleteDataPersonAssoc fname searchVal = catch ( do { 
							handle <- openFile fname ReadWriteMode;
							contents <- hGetContents handle;
							contents2 <- return $! (contents);
							hClose handle;
							handle <- openFile fname WriteMode;
							deleteRowPersonAssoc handle contents2 searchVal False 2 ;
							hClose handle;
						} ) errorHandler
						where
							errorHandler e = ioError e
							
-- funkcja sluzaca do usuniecia danych osoby z asocjacji, wyszukuje wiersz na podstawie podanej kolumny searchByColumn i usuwa wiesz
deleteRowPersonAssoc hdl contents searchVal debug searchByColumn  = do {
							if (findPattern contents ("\n")) then do {
								if (findPatternEx searchVal (getColumn (getRow contents) searchByColumn)) then do {
									hPutStrLn hdl "" ;
									contents <- return(removeRow contents);
									deleteRowPersonAssoc hdl (noNewLine (removeRow contents)) searchVal True searchByColumn ;
								}
								else do {
									hPutStrLn hdl (getRow contents);
									deleteRowPersonAssoc hdl (noNewLine (removeRow contents)) searchVal debug searchByColumn ;
								}
							}
							else 
								if (debug==False) then
									putStrLn ("Nie znaleziono wpisu: "++searchVal)
								else 
									putStrLn ("Wpis "++searchVal++" zostal usuniety");
						}

-- funkcja sluzaca do modyfikacji danych osoby
modifyDataPerson fname searchVal newColVal modifyColumn = catch ( do { 
							handle <- openFile fname ReadWriteMode;
							contents <- hGetContents handle;
							contents2 <- return $! (contents);
							hClose handle;
							handle <- openFile fname WriteMode;
							modifyRowPerson handle contents2 searchVal newColVal False 4 modifyColumn;
							hClose handle;
						} ) errorHandler
						where
							errorHandler e = ioError e
							
-- funkcja sluzaca do modyfikacji danych wyszukuje wiersz na podstawie podanej kolumny searchByColumn i modyfikuje kolumnę
modifyRowPerson hdl contents searchVal newColVal debug searchByColumn modifyColumn = do {
							if (findPattern contents ("\n")) then do {
								if (findPatternEx searchVal (getColumn (getRow contents) searchByColumn)) then do {
									hPutStrLn hdl (swapInColumn (getRow contents) newColVal modifyColumn 6 1 ) ;
									contents <- return(removeRow contents);
									modifyRowPerson hdl (noNewLine (removeRow contents)) searchVal newColVal True searchByColumn modifyColumn;
								}
								else do {
									hPutStrLn hdl (getRow contents);
									modifyRowPerson hdl (noNewLine (removeRow contents)) searchVal newColVal debug searchByColumn modifyColumn;
								}
							}
							else 
								if (debug==False) then
									putStrLn ("Nie znaleziono wpisu: "++searchVal)
								else if (newColVal=="") then
									putStrLn ("Wpis "++searchVal++" zostal usuniety")
								else do {
									--putStrLn ("Poprzednia wartosc: "++searchVal);
									putStrLn ("Obecna wartosc: "++newColVal);
								}
						}
						
-- funkcja sluzaca do modyfikacji numeru telefonu osoby w asocjacjach
modifyDataPersonPhoneAssoc fname searchVal newColVal = catch ( do { 
							handle <- openFile fname ReadWriteMode;
							contents <- hGetContents handle;
							contents2 <- return $! (contents);
							hClose handle;
							handle <- openFile fname WriteMode;
							modifyRowPersonPhoneAssoc handle contents2 searchVal newColVal False 2 2;
							hClose handle;
						} ) errorHandler
						where
							errorHandler e = ioError e
							
-- funkcja sluzaca do modyfikacji danych w asocjacjach wyszukuje wiersz na podstawie podanej kolumny searchByColumn i modyfikuje kolumnę
modifyRowPersonPhoneAssoc hdl contents searchVal newColVal debug searchByColumn modifyColumn = do {
							if (findPattern contents ("\n")) then do {
								if (findPatternEx searchVal (getColumn (getRow contents) searchByColumn)) then do {
									hPutStrLn hdl (swapInColumn (getRow contents) newColVal modifyColumn 2 1 ) ;
									contents <- return(removeRow contents);
									modifyRowPersonPhoneAssoc hdl (noNewLine (removeRow contents)) searchVal newColVal True searchByColumn modifyColumn;
								}
								else do {
									hPutStrLn hdl (getRow contents);
									modifyRowPersonPhoneAssoc hdl (noNewLine (removeRow contents)) searchVal newColVal debug searchByColumn modifyColumn;
								}
							}
							else 
								if (debug==False) then
									putStrLn ("Nie znaleziono wpisu: "++searchVal)
								else if (newColVal=="") then
									putStrLn ("Wpis "++searchVal++" zostal usuniety")
								else do {
									putStrLn ("Poprzednia wartosc: "++searchVal);
									putStrLn ("Obecna wartosc: "++newColVal);
								}
						}
						
--funkcja służąca do podmiany wartości w danej kolumnie, newVal = nowa wartosc dla kolumny, swapCol = numer kolumny ktora zmieniamy, numCol = liczba kolumn pozostałych do przetworzenia w swapInColumn, currCol = numer bieżącej kolumny
swapInColumn _ _ _ 0 _ = ""
swapInColumn row newVal swapCol numCol currCol 	= if swapCol == 1 then newVal++" "++(swapInColumn row newVal (swapCol-1) (numCol-1) (currCol+1))
											else  (getColumn row currCol)++" "++(swapInColumn row newVal (swapCol-1) (numCol-1) (currCol+1))

-- funkcja scala grupy o podanych symbolach, grupa fromGroupSymbol zostanie dołączona do grupy toGroupSymbol
-- tutaj nastepuje sprawdzenie argumentow
mergeGroups fromGroupSymbol toGroupSymbol = catch( do {
							hand <- openFile "d:/groups.txt" ReadWriteMode;
							yg <- existingGroup hand [];
							hClose hand;
							if (not (findPattern fromGroupSymbol toGroupSymbol)) then do
							{
							if (elem (fromGroupSymbol, "0") yg) then do 
								{
									if (elem (toGroupSymbol, "0") yg) then do 
									{
										doMoveGroup "d:/groupspersons.txt" fromGroupSymbol toGroupSymbol;
									}
									else putStrLn "Grupa docelowa nie istnieje";
								}
								else putStrLn "Grupa źródłowa nie istnieje";
							} else putStrLn "Grupa docelowa nie może być grupą źródłową";
						} ) errorHandler
						where
							errorHandler e = ioError e
-- funkcja przenosi kontakty z fromGroupSymbol do toGroupSymbol, nie sprawdza poprawnosci argumentow
doMoveGroup fname fromGroupSymbol toGroupSymbol = catch ( do {
							handle <- openFile fname ReadWriteMode;
							mergeSearchByGroup handle fromGroupSymbol toGroupSymbol [];
							--hClose handle;
						} ) errorHandler
						where
							errorHandler e = ioError e
							
-- funkcja wykonuje rekurencyjnie poszukiwanie kontaktów należących do grupy źródłowej (fromGroupSymbol) i na koniec dopisuje asocjacje osób do nowej grupy
mergeSearchByGroup hdl fromGroupSymbol toGroupSymbol listNewAssoc = do {
							t <- hIsEOF hdl;							
							if t then do {
								hClose hdl;
								saveRowListToHandle hdl listNewAssoc; -- zapisanie nowych asocjacji w pliku
							}
							else do {
								contents <- hGetLine hdl;
								x<-return(contents);
								if x == [] then				--zabezpieczenie przed pustymi wierszami w pliku
									mergeSearchByGroup hdl fromGroupSymbol toGroupSymbol listNewAssoc
								else if (findPatternEx (getColumn x 1) fromGroupSymbol) then do {
									mergeSearchByGroup hdl fromGroupSymbol toGroupSymbol ((toGroupSymbol++" "++(getColumn x 2)):listNewAssoc);
								}
								else
									mergeSearchByGroup hdl fromGroupSymbol toGroupSymbol listNewAssoc;
							}
						}
						
-- funkcja rekurencyjna do zapisywania listy wierszy do pliku
saveRowListToHandle _ [] = do {
							putStr "";
						}
saveRowListToHandle hdl (el:listNewAssoc) = catch( do {
							if not (null (el:listNewAssoc)) then do{
								saveRow "d:/groupspersons.txt" el;
								saveRowListToHandle hdl listNewAssoc;
							} else do {
								putStr "";
							};
						} ) errorHandler
						where
							errorHandler e = ioError e

-- funkcja usuwa asocjacje związane z grupą
deleteGroupAssoc symbol = catch( do {
							hand <- openFile "d:/groupspersons.txt" ReadWriteMode;
							y <- existingAssociationSymbol hand [];
							hClose hand;
							oldRowCol <- return(symbol);
							if (elem (symbol) y) then do 
							{
								modifyData "d:/groupspersons.txt" oldRowCol "";
							}
							else putStrLn "";
						} ) errorHandler
						where
							errorHandler e = ioError e

-- funkcja usuwa grupę
deleteGroup symbol = catch( do {
							hand <- openFile "d:/groups.txt" ReadWriteMode;
							y <- existingGroup hand [];
							hClose hand;
							oldRowCol <- return(symbol);
							if (elem (symbol, "0") y) then do 
							{
								modifyData "d:/groups.txt" oldRowCol "";
							}
							else putStrLn "Wskazana grupa nie istnieje";
						} ) errorHandler
						where
							errorHandler e = ioError e

-- funkcja przeszukuje osoby po kryterium przynależności do grupy kontaktów (w pliku o podanej nazwie)
findByGroup fname pattern bool = catch ( do {
							handle <- openFile fname ReadWriteMode;
							searchByGroup handle pattern 1 False;
							hClose handle;
						} ) errorHandler
						where
							errorHandler e = ioError e
-- funkcja przeszukuje osoby po kryterium przynależności do grupy kontaktów (w pliku o podanym uchwycie)					
searchByGroup hdl str i bool = do {
							t <- hIsEOF hdl;							
							if t then do {
								if (bool==False) then
									putStrLn "Nie znaleziono osoby spelniajacej kryteria"
								else
									putStrLn "";
							}
							else do {
								contents <- hGetLine hdl;
								x<-return(contents);
								if x == [] then				--zabezpieczenie przed pustymi wierszami w pliku
									searchByGroup hdl str i bool
								else if (findPatternEx (getColumn x i) str) then do { 	--sprawdzenie czy dana linijka pasuje do wzorca
									--putStrLn ("Szukanie "++(getColumn x 2));
									findBy "d:/persons.txt" (getColumn x 2) 4 False;	-- wyszukanie osób o numerze telefonu podanym w asocjacji
									searchByGroup hdl str i True;
								}
								else
									searchByGroup hdl str i bool;
							}
						}

-- funkcja sluzaca do wyszukiwania informacji w pliku okreslonej przez pattern - tekst  a jaki mamy wyszukac
-- i numer kolumny (kategorii) w jakiej mamy szukac odpowiada za to funkcja search
findBy fname pattern i bool = catch ( do {
							handle <- openFile fname ReadWriteMode;
							search handle pattern i False;
							hClose handle;
						} ) errorHandler
						where
							errorHandler e = ioError e

-- funkcja search wyszukuje wzoraca okreslonego przez str w kolumnie i 						 
search hdl str i bool = do {
							t <- hIsEOF hdl;							
							if t then do {
								if (bool==False) then
									putStrLn "Nie znaleziono osoby spelniajacej kryteria"
								else 
									putStrLn "";
							}
							else do {
								contents <- hGetLine hdl;
								x<-return(contents);
								if x == [] then				--zabezpieczenie przed pustymi wierszami w pliku
									search hdl str i bool
								else if (findPatternEx (getColumn x i) str) then do { 	--sprawdzenie czy dana linijka pasuje do wzorca
									putStrLn x;
									search hdl str i True;
								}
								else
									search hdl str i bool;
							}
						}

-- funkcja modyfikuje asocjację
modifyGroupAssoc oldSymbol newSymbol = catch( do {
							hand <- openFile "d:/groupspersons.txt" ReadWriteMode;
							y <- existingAssociationSymbol hand [];
							hClose hand;
							if (elem (oldSymbol) y ) then do
							{
								modifyData "d:/groupspersons.txt" oldSymbol newSymbol;
							}
							else putStrLn "Podano błędne dane";
						} ) errorHandler
						where													--zabezpieczenie przed nieistniejacym plikiem
							errorHandler e = ioError e
							
-- funkcja sluzaca do modyfikacji danych w pliku z asocjacjami, podmienia tylko kolumnę
modifyRowAssoc hdl contents rowcol newrowcol debug = do {
							if (findPattern contents ("\n")) then do {
								if (findPatternEx (rowcol++" ") (getRow contents)) then do {
									contents <- return(removeRow contents);
									newrow <- return(newrowcol++" "++(getColumn contents 2));
									hPutStrLn hdl newrow;
									modifyRowAssoc hdl (noNewLine (removeRow contents)) rowcol newrowcol True;
								}
								else do {
									--putStrLn (getRow contents);
									hPutStrLn hdl (getRow contents);
									modifyRowAssoc hdl (noNewLine (removeRow contents)) rowcol newrowcol debug;
								}
							}
							else 
								if (debug==False) then
									putStrLn ("Nie znaleziono wpisu: "++rowcol)
								else if (newrowcol=="") then
									putStrLn ("Wpis "++rowcol++" zostal usuniety")
								else do {
									putStrLn ("Poprzednia wartosc: "++rowcol);
									putStrLn ("Obecna wartosc: "++newrowcol);
								}
						}
						
-- funkcja modyfikuje grupę
modifyGroup oldSymbol newSymbol newName = catch( do {
							hand <- openFile "d:/groups.txt" ReadWriteMode;
							y <- existingGroup hand [];
							hClose hand;
							old_row <- return(oldSymbol++" ");
							new_row <- return(newSymbol++" "++newName);
							if (elem (oldSymbol, "0") y ) then do
							{
								modifyData "d:/groups.txt" old_row new_row;
							}
							else putStrLn "Podano błędne dane";
						} ) errorHandler
						where													--zabezpieczenie przed nieistniejacym plikiem
							errorHandler e = ioError e
							
-- funkcja sluzaca do modyfikacji danych
modifyData fname row newrow = catch ( do { 
							handle <- openFile fname ReadWriteMode;
							contents <- hGetContents handle;
							contents2 <- return $! (contents);
							hClose handle;
							handle <- openFile fname WriteMode;
							modifyRow handle contents2 row newrow False;
							hClose handle;
						} ) errorHandler
						where
							errorHandler e = ioError e
							
-- funkcja sluzaca do modyfikacji danych wyszukuje wiersz lub jego czesc (row) i zamienia go na newrow													
modifyRow hdl contents row newrow debug = do {
							if (findPattern contents ("\n")) then do {
								if (findPattern (getRow contents) row) then do {
									contents <- return(removeRow contents);
									hPutStrLn hdl newrow;
									modifyRow hdl (noNewLine (removeRow contents)) row newrow True;
								}
								else do {
									--putStrLn (getRow contents);
									hPutStrLn hdl (getRow contents);
									modifyRow hdl (noNewLine (removeRow contents)) row newrow debug;
								}
							}
							else 
								if (debug==False) then
									putStrLn ("Nie znaleziono wpisu: "++row)
								else if (newrow=="") then
									putStrLn ("Wpis "++row++" zostal usuniety")
								else do {
									putStrLn ("Poprzednia wartosc: "++row);
									putStrLn ("Obecna wartosc: "++newrow);
								}
						}
						
-- funkcja pobiera wiersz z zawartosci xs takeWhile do znaku nowej linii
getRow [] = [];		
getRow (xs) = do {
				takeWhile (/='\n') xs;
			}
						
-- fukncja usuwa wiersz - dropWhile do znaku nowej lini (trzeba pozniej uzyc noNewLine) 		
removeRow [] = [];
removeRow (xs) = do {
				dropWhile (/='\n') xs;
			}
						
-- funkcja szuka wzorca okreslonego przez x:xs w tekscie y:ys
findPattern [] [] = True
findPattern _ [] = True
findPattern [] _ = False							
findPattern (x:xs) (y:ys) = if x==y then findPattern xs ys 
							 else findPattern xs (y:ys)
							 
-- funkcja dokładnego porównywania
findPatternEx [] [] = True
findPatternEx _ [] = True
findPatternEx [] _ = False							
findPatternEx (x:xs) (y:ys) = if x==y then findPatternEx xs ys 
							 else False
						
-- funkcja pobiera i-te pole z wiersza (krotki) xs
-- separatorami sa spacje
getColumn (xs) i = do {
							if (i==1) then
								takeWhile (/=' ') xs
							else
								getColumn (noSpace (dropWhile (/=' ') xs)) (i-1);
						}
						
-- funkcja pomocnicza usuwajaca pierwszy znak
noSpace [] = [];
noSpace (x:xs) = xs;
noNewLine (x:xs) = xs;

-- funcka dodaje nową osobę do pliku
addPerson name surname company phone mail birth  = catch(
							do {			
								hand <- openFile "d:/persons.txt" ReadWriteMode;
								y <- existingPersonPhone hand [];
								hClose hand;
								if ( not (elem phone y) ) then do 
								{
								saveRow   "d:/persons.txt" (name++" "++surname++" "++company++" "++phone++" "++mail++" "++birth);
								putStrLn ("Nowa osoba zostala dodana");
								}
								else putStrLn "Osoba o podanym numerze istnieje już w spisie";
									
							} 
						) errorHandler
						where
							errorHandler e = ioError e
							
-- funkcja dodaje nową grupę do pliku
addGroup grSymbol name  = catch(
							do {			
								hand <- openFile "d:/groups.txt" ReadWriteMode;
								y <- existingGroup hand [];
								hClose hand;
								if ( not (elem (grSymbol,"0") y) ) then do 
								{
								saveRow "d:/groups.txt" (grSymbol++" "++name);
								putStrLn ("Nowa grupa zostala dodana");
								}
								else putStrLn "Grupa istnieje już w spisie";
									
							} 
						) errorHandler
						where
							errorHandler e = ioError e
							
-- funkcja dodaje nową asocjację do pliku (wiąże osobę z grupą)
addGroupAssociation groupSymbol phone  = catch(
							do {			
								hand <- openFile "d:/groupspersons.txt" ReadWriteMode;
								ya <- existingAssociationPhone hand [];
								hClose hand;
								hand <- openFile "d:/persons.txt" ReadWriteMode;
								yp <- existingPersonPhone hand [];
								hClose hand;
								hand <- openFile "d:/groups.txt" ReadWriteMode;
								yg <- existingGroup hand [];
								hClose hand;
								if (elem (groupSymbol,"0") yg) then do
								{
									if (elem (phone) yp) then do
									{
										if ( not (elem (groupSymbol,phone) ya) ) then do
										{
											saveRow   "d:/groupspersons.txt" (groupSymbol++" "++phone);
											putStrLn ("Nowa asocjacja zostala dodana");
										}
										else putStrLn "Asocjacja istnieje już w spisie";
									}
									else putStrLn "Osoba nie istnieje";
								}
								else putStrLn "Grupa nie istnieje";
							} 
						) errorHandler
						where
							errorHandler e = ioError e


					 
--funkcja odpowiadajaca za wczytanie plikow	
printFile fname = catch( do {
							handle <- openFile fname ReadWriteMode;
							printRow handle;
							hClose handle;
						} ) errorHandler
						where
							errorHandler e = ioError e

-- wyswietla wszystkie wiersze pliku do ktorego podano handle - uchwyt
printRow handle = do {
							t <- hIsEOF handle;						
							if t then return()
							else do {
								contents <- hGetLine handle;
								x<-return(contents);
								if x == [] then return()
								else putStrLn contents;
								printRow handle 
							}
						}
						
-- zapisuje wiersz do pliku					 
saveRow fname contents = catch ( do {
										handle <- openFile fname AppendMode;
										hPutStrLn handle contents;
										hClose handle
								} ) errorHandler
								where
										errorHandler e = ioError e	

-- zapisuje wiersz do handle
saveRowToHandle handle contents = catch ( do {
										hPutStrLn handle contents;
								} ) errorHandler
								where
										errorHandler e = ioError e
	 
-- funkcja zwraca liste par (imie , nr_telefonu)
existingPerson hdl (xs) = do {
                                                        t <- hIsEOF hdl;
                                                        if (t) then return xs
                                                        else do {
                                                                cont <- hGetLine hdl;
                                                                x <- return(cont);
                                                                if x==[] then existingPerson hdl xs
                                                                else existingPerson hdl ( (words x !! 0,words x !! 3): xs);
                                                        }
                                                }
-- funkcja zwraca liste tupli (phone)										
existingPersonPhone hdl (xs) = do {
                                                        t <- hIsEOF hdl;
                                                        if (t) then return xs
                                                        else do {
                                                                cont <- hGetLine hdl;
                                                                x <- return(cont);
                                                                if x==[] then existingPersonPhone hdl xs
                                                                else existingPersonPhone hdl ( (words x !! 3): xs);
                                                        }
                                                }			
												
												
-- funkcja zwraca liste tupli (groupSymbol,"0")
existingGroup hdl (xs) = do {
                                                        t <- hIsEOF hdl;
                                                        if (t) then return xs
                                                        else do {
                                                                cont <- hGetLine hdl;
                                                                x <- return(cont);
                                                                if x==[] then existingGroup hdl xs
                                                                else existingGroup hdl ( (words x !! 0, "0"): xs);
                                                        }
                                                }
												
-- funkcja zwraca liste tupli (groupSymbol,name,phone)
existingAssociation hdl (xs) = do {
                                                        t <- hIsEOF hdl;
                                                        if (t) then return xs
                                                        else do {
                                                                cont <- hGetLine hdl;
                                                                x <- return(cont);
                                                                if x==[] then existingAssociation hdl xs
                                                                else existingAssociation hdl ( (words x !! 0,words x !! 1,words x !! 2): xs);
                                                        }
                                                }
												
-- funkcja zwraca liste tupli (groupSymbol,phone)
existingAssociationPhone hdl (xs) = do {
                                                        t <- hIsEOF hdl;
                                                        if (t) then return xs
                                                        else do {
                                                                cont <- hGetLine hdl;
                                                                x <- return(cont);
                                                                if x==[] then existingAssociationPhone hdl xs
                                                                else existingAssociationPhone hdl ( (words x !! 0,words x !! 1): xs);
                                                        }
                                                }
												
-- funkcja zwraca liste tupli (groupSymbol)
existingAssociationSymbol hdl (xs) = do {
                                                        t <- hIsEOF hdl;
                                                        if (t) then return xs
                                                        else do {
                                                                cont <- hGetLine hdl;
                                                                x <- return(cont);
                                                                if x==[] then existingAssociationSymbol hdl xs
                                                                else existingAssociationSymbol hdl ( (words x !! 0): xs);
                                                        }
    }

													
-- wzorce do sprawdzania danych wejściowych
daty = "^(18|19|20)[0-9][0-9][-](0[1-9]|1[012])[-](0[1-9]|[12][0-9]|3[01])$" 
litery = "^[a-zA-Z][a-zA-Z]*$"

telefony = "^[123456789][0123456789]{8}$"

mail = "^([a-zA-Z0-9]+\\.)*[a-zA-Z0-9]+@([a-zA-Z0-9]+\\.)*[a-zA-Z0-9]+\\.[a-zA-Z]{2,5}$"

--funkcja sprawdza poprawność pobieranych danych od użytkownika 
checkPattern pattern prompt = do
			 putStrLn prompt
			 elem <- getLine
			 if elem =~ pattern :: Bool then return(elem)
			 else do
				 putStrLn "Bledne dane, sprobuj ponownie !"
				 checkPattern pattern prompt




-- funkcja zwraca liste tupli, którzy obchodzą urodziny(imie,nazwisko,firma,data)
findingBirthDay hdl (xs) = do {
                                                        t <- hIsEOF hdl;
                                                        if (t) then return xs
                                                        else do {
                                                                cont <- hGetLine hdl;
                                                                x <- return(cont);
                                                                if x==[] then findingBirthDay hdl xs
                                                                else do { 
																    a<-return (removeYear $ words x !! 5);
																	b<-getDate;
																	c<-return (removeYear b);
																	if a == c then findingBirthDay hdl ( (words x !! 0,words x !! 1,words x !! 2,removeYear $ words x !! 5 ): xs);
																	else findingBirthDay hdl xs
																}
														}
                                                }
--funkcja usuwana rok z formatu YYYY-MM-DD do formatu MM-DD
removeYear [] = []
removeYear [x] = []
removeYear (x:xs) = if x =='-' then xs
			     else removeYear xs
--funkcja pobiera aktualną datę w formacie YYYY-MM-DD				 
getDate = do
    now <- getCurrentTime
    return (formatTime defaultTimeLocale "%F" now)

--funkcje drukują Jubilatów
showDetails (name, surname, firm, _) =  name ++" "++ surname ++" z firmy "++ firm ++" obchodzi urodziny !"

printingJubilat list = putStrLn . unlines . map showDetails $ list			
										